package com.actionpals.utils
{
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.TimerEvent;

	public class FrameTimer extends EventDispatcher
	{
		/**
		 * @private
		 */		
		protected var _stage:Stage;
		
		/**
		 * @private
		 */	
		protected var _currentCount:int;
		
		/**
		 * @private
		 */	
		protected var _delay:int;
		
		/**
		 * @private
		 */	
		protected var _repeatCount:int;
		
		/**
		 * @private
		 */	
		protected var _running:Boolean;
		
		private var frameCount:int = 0;
		
		public function FrameTimer( stage:Stage, delay:int, repeatCount:int = 0 )
		{
			_stage = stage;
			_delay = delay;
			_repeatCount = repeatCount;
			
			super( null );
		}
		
		/**
		 * The stage object is needed in order to listen for enterframe events.  This
		 * needs to be set inorder for FrameTimer to function properly.
		 */
		public function get stage():Stage
		{
			return _stage;
		}
		
		/**
		 * @private
		 */		
		public function set stage( value:Stage ):void
		{
			_stage = value;
		}
		
		/**
		 * The total number of times the timer has fired since it started at zero.
		 */
		public function get currentCount():Stage
		{
			return _stage;
		}
		
		/**
		 * The delay, in frames, between timer events.
		 */
		public function get delay():int
		{
			return _delay;
		}
		
		/**
		 * @private
		 */		
		public function set delay( value:int ):void
		{
			_delay = value;
		}
		
		/**
		 * The total number of times the timer is set to run.
		 */
		public function get repeatCount():int
		{
			return _repeatCount;
		}
		
		/**
		 * @private
		 */		
		public function set repeatCount( value:int ):void
		{
			_repeatCount = value;
		}
		
		/**
		 * The timer's current state; true if the timer is running, otherwise false.
		 */
		public function get running():Boolean
		{
			return _running;
		}
		
		/**
		 * Stops the timer, if it is running, and sets the currentCount property back to 0,
		 * like the reset button of a stopwatch.
		 */
		public function reset():void
		{
			if( _running ) stop();
			_currentCount = 0;
		}
		
		/**
		 * Starts the timer, if it is not already running.
		 */
		public function start():void
		{
			_running = true;
			stage.addEventListener( Event.ENTER_FRAME, onEnterFrame );
		}
		
		/**
		 * Stops the timer.
		 */
		public function stop():void
		{
			_running = false;
			stage.removeEventListener( Event.ENTER_FRAME, onEnterFrame );
		}
		
		/**
		 * @private
		 */		
		protected function frameCheck():void
		{
			if( ( frameCount % _delay ) == 0 )
			{
				_currentCount++;
				
				dispatchEvent( new TimerEvent( TimerEvent.TIMER ) );
				
				if( _currentCount >= _repeatCount )
				{
					stop();
					dispatchEvent( new TimerEvent( TimerEvent.TIMER_COMPLETE ) );
				}
			}
		}
		
		/**
		 * @private
		 */
		protected function onEnterFrame( event:Event ):void
		{
			frameCount++;
			frameCheck();
		}		
	}
}